<template>
  <div class="app-container">
    <el-container>
      <el-drawer
        direction="rtl"
        :title="gridType.title"
        :visible.sync="drawerVisible"
      >
        <el-tabs v-model="activeName" type="card">
          <el-tab-pane label="历史图层" name="first">
            <div class="d-flex" slot="label">
              <span class="mr12">历史图层</span>
              【
              <el-link
                icon="el-icon-plus"
                size="mini"
                type="primary"
                @click="handleAddCell"
              >
                新建图层
              </el-link>
              】 【
              <el-link
                icon="el-icon-refresh"
                size="mini"
                type="primary"
                @click="getGrids"
              >
                刷新
              </el-link>
              】
            </div>
            <el-table
              :data="gridPartitions"
              :height="360"
              stripe
              style="width: 100%"
              @row-click="handleDetail"
            >
              <el-table-column
                align="center"
                label="选中"
                prop="name"
                width="80"
              >
                <template #default="{ row }">
                  <i
                    v-if="row.id === currentLayer.id"
                    class="el-icon-check font24 color-success"
                  ></i>
                  <i v-else class="el-icon-close font24 color-danger"></i>
                </template>
              </el-table-column>
              <el-table-column align="center" label="名称" prop="name" />
              <el-table-column
                align="center"
                label="创建者"
                prop="created_user"
              />
              <el-table-column
                align="center"
                label="创建时间"
                prop="created_at"
                show-overflow-tooltip
              />
              <el-table-column align="center" fixed="right" label="操作">
                <template #default="{ row }">
                  <el-link type="danger" @click.stop="handleDelete(row)">
                    删除
                  </el-link>
                </template>
              </el-table-column>
            </el-table>
          </el-tab-pane>
          <el-tab-pane label="参数设置" name="second">
            <grid-set :grid-type="gridType" @updateGridType="updateGridType" />
          </el-tab-pane>
        </el-tabs>
        <div class="h24"></div>
        <el-divider content-position="left">
          <span class="font-bold color-primary">
            历史分区
            <el-button class="ml12" size="mini" type="success" @click="cellSet">
              分区设置
            </el-button>
            【
            <el-link
              icon="el-icon-refresh"
              size="mini"
              type="primary"
              @click="getGridPartitions"
            >
              刷新
            </el-link>
            】
          </span>
        </el-divider>
        <el-table :data="grids" :height="360" stripe style="width: 100%">
          <el-table-column
            align="center"
            label="创建者"
            prop="created_user"
            width="100"
          />
          <el-table-column
            align="center"
            label="创建时间"
            prop="created_at"
            show-overflow-tooltip
          />
          <el-table-column
            align="center"
            label="生效分区"
            prop="active"
            width="100"
          >
            <template #default="{ row }">
              <i
                v-if="row.valid"
                class="el-icon-check font24 color-success"
              ></i>
              <i v-else class="el-icon-close font24 color-danger"></i>
            </template>
          </el-table-column>
          <el-table-column align="center" fixed="right" label="操作">
            <template #default="{ row }">
              <el-link class="mr12" type="primary" @click="handleEdit(row)">
                设为生效分区
              </el-link>
              <el-link type="danger" @click="handleDelGrid(row)">删除</el-link>
            </template>
          </el-table-column>
        </el-table>
      </el-drawer>
      <el-main class="full-height" style="padding: 0">
        <div class="full-height" style="position: relative">
          <div id="map-multi" ref="map" style="width: 100%; height: 872px" />
          <div class="tooltip" @click="drawerVisible = true">
            <span class="iconfont icon-pianqu"></span>
            <span>显示详情</span>
          </div>
          <div class="colors">
            <dl
              v-for="(item, index) in gridType.steps"
              :key="index"
              class="flex"
              @click="changeStep(item.step)"
            >
              <dt
                class="d-flex align-items-center"
                :style="{ background: item.color }"
              >
                <i
                  class="mr4 font20"
                  :class="
                    +item.step === +step
                      ? 'el-icon-circle-check'
                      : 'el-icon-remove-outline'
                  "
                />
                <span>{{ item.value }}</span>
              </dt>
            </dl>
          </div>
          <div v-if="layers.length > 0" class="btn-container">
            <el-button size="medium" type="primary" @click="drawFinish">
              完成绘制
            </el-button>
          </div>
        </div>
      </el-main>
    </el-container>
    <el-dialog title="载入数据文件" :visible.sync="dialogVisible" width="800px">
      <el-empty v-if="tableData.length === 0" description="暂无任何计算结果">
        <file-upload :action="uploadUrl" :name="name" @onSuccess="onSuccess" />
      </el-empty>
      <div v-else>
        <div class="tip">
          <el-descriptions
            border
            class="margin-top"
            :column="3"
            content-class-name="contentClass"
            label-class-name="labelClass"
          >
            <el-descriptions-item
              v-for="(item, index) in centroids"
              :key="item"
              :label="index"
            >
              {{ item[0].toFixed(4) }}
            </el-descriptions-item>
          </el-descriptions>
        </div>
        <div class="h12"></div>
        <el-table
          border
          :data="tableData"
          :height="600"
          stripe
          style="width: 100%"
        >
          <el-table-column align="center" label="经度" prop="lng" />
          <el-table-column align="center" label="纬度" prop="lat" />
          <el-table-column
            align="center"
            label="值"
            prop="value"
            show-overflow-tooltip
          />
          <el-table-column align="center" label="分类" prop="labels" />
        </el-table>
        <div class="h12" />
        <div>
          <el-button type="primary" @click="addOne">保存</el-button>
          <el-button type="default" @click="reCompute">重置</el-button>
        </div>
      </div>
    </el-dialog>
    <el-dialog
      append-to-body
      title="输入名称"
      :visible.sync="dialogAddVisible"
      width="30%"
    >
      <el-input v-model="postData.name" clearable placeholder="名称" />
      <div class="h12" />
      <el-button type="primary" @click="submit">提交</el-button>
    </el-dialog>
    <cell-set ref="cellSet" />
  </div>
</template>

<script>
  import GridSet from '@/components/GridSet'
  import CellSet from '@/components/CellSet'
  import FileUpload from '@/components/FileUpload'
  import { addOne } from '@/api/gridPartition'
  import { map, cellsSprinkler, dclassCodeMap } from '@/utils/constant'
  // eslint-disable-next-line no-unused-vars
  import { deepClone, arraySort, convertArr2Obj, uniqueArr } from '@/utils'
  import * as turf from '@turf/turf'
  import { mapGetters } from 'vuex'
  import {
    getGridType,
    updateGridType,
    getGrids,
    getGridPartitions,
    addGrid,
    activeGrid,
    deleteGridPartition,
    deleteGrid,
  } from '@/api/device'
  export default {
    components: {
      GridSet,
      CellSet,
      FileUpload,
    },
    props: {
      name: {
        type: String,
        default() {
          return 'multi'
        },
      },
      gridTypeId: {
        type: Number,
        default() {
          return 4
        },
      },
    },
    data() {
      return {
        drawerVisible: false,
        currentLayer: {},
        activeName: 'first',
        step: 3,
        centroids: [],
        tableData: [],
        uploadUrl: 'https://api.zesi.com.cn/idata/util/upload',
        dialogVisible: false,
        zoom: map.zoom,
        center: map.center,
        options: map.options,
        urls: map.mapTypes[map.initType],
        cellsSprinkler: cellsSprinkler,
        gridPartitions: [],
        grids: [],
        field: {
          id: 6,
          longitude: 37.467294,
          latitude: 114.913504,
          radius: 150,
        },
        ruleForm: {
          serialno: '',
          angle: 30,
          startAngle: 0,
          endAngle: 360,
          distances: [
            12.5, 22.5, 32.5, 42.5, 52.5, 62.5, 72.5, 82.5, 92.5, 102.5, 112.5,
            122.5, 132.5, 142.5, 150,
          ],
        },
        polygons: [],
        circlePolygons: [],
        polygonsIntersect: [],
        layers: [],
        gridType: {},
        featureLayerGroup: null,
        baseLayers: [],
        relation: {},
        circleLayer: null,
        map: null,
        dialogAddVisible: false,
        postData: {
          name: '',
          grid_type_id: '',
          data: null,
          datetimerange: null,
        },
      }
    },
    computed: {
      ...mapGetters(['devices', 'project', 'username']),
      sprinklers() {
        return (
          this.devices.filter((val) => {
            return +val.product_type === +dclassCodeMap.pg
          }) || []
        )
      },
      cellsFormat() {
        const cellsSprinkler = deepClone(this.cellsSprinkler)
        return arraySort(cellsSprinkler, 'disend')
      },
      stepsObj() {
        return convertArr2Obj(this.gridType.steps, 'step')
      },
      stepsObjByLabels() {
        return convertArr2Obj(this.gridType.steps, 'labels')
      },

      circlePolygon() {
        const center = [this.project.lng, this.project.lat]
        const radius = 0.15
        const options = {
          steps: 100,
          units: 'kilometers',
          properties: { foo: 'bar' },
        }
        return turf.circle(center, radius, options)
      },
      colors() {
        const res = []
        this.gridType.steps.forEach((item) => {
          res.push({ fill: item.color })
        })
        res.push(res[res.length - 1])
        return res
      },
      levelV() {
        const res = []
        this.gridType.steps.forEach((item, index) => {
          if (index < this.gridType.steps.length - 1) {
            res.push(item.lower)
          } else {
            res.push(item.lower)
            res.push(item.upper)
          }
        })
        return res
      },
    },
    watch: {
      sprinklers: {
        handler(newVal) {
          if (newVal.length > 0) {
            const sprinkler = newVal[0]
            const { serialno, angle, startAngle, endAngle, distances } =
              sprinkler.settings
            this.ruleForm.serialno = serialno
            this.ruleForm.angle = angle
            this.ruleForm.startAngle = startAngle
            this.ruleForm.endAngle = endAngle
            this.ruleForm.distances = distances || []
          }
        },
        deep: true,
        immediate: true,
      },
    },
    mounted() {
      this.initMap()
    },
    created() {
      this.getGridType(this.gridTypeId)
      this.getGridPartitions()
      this.getGrids()
    },
    methods: {
      handleDelete(row) {
        this.$baseConfirm(
          '确定删除该分区吗？',
          '提示',
          async () => {
            const { msg } = await deleteGridPartition(row.id)
            this.getGridPartitions()
            this.$baseMessage(msg, 'success', 'vab-hey-message-success')
          },
          () => {}
        )
      },
      async handleDelGrid(row) {
        this.$baseConfirm(
          '确定删除该分区吗？',
          '提示',
          async () => {
            const { msg } = await deleteGrid(row.id)
            this.getGrids()
            this.$baseMessage(msg, 'success', 'vab-hey-message-success')
          },
          () => {}
        )
      },
      reCompute() {
        this.tableData = []
        this.centroids = []
      },
      addOne() {
        this.dialogAddVisible = true
      },
      async submit() {
        this.postData.grid_type_id = this.gridTypeId
        this.postData.data = this.tableData
        this.postData.centroids = this.centroids
        this.postData.field_id = 6
        if (!this.postData.name) {
          this.$message.error('请输入名称')
        }
        this.postData.created_user = this.username
        const { msg } = await addOne(this.postData)
        this.getGridPartitions()
        this.getGrids()
        this.$message.success(msg)
        this.dialogAddVisible = false
        this.dialogVisible = false
      },
      async activeGrid(id) {
        const { msg } = await activeGrid(id)
        this.$baseMessage(msg, 'success', 'vab-hey-message-success')
        this.getGrids()
      },
      async addGrid(postData) {
        const { data, msg } = await addGrid(postData)
        this.activeGrid(data.id)
        this.$baseMessage(msg, 'success', 'vab-hey-message-success')
        this.getGrids()
      },
      changeStep(step) {
        this.step = step
      },
      initMap() {
        this.urls.forEach((item) => {
          // eslint-disable-next-line no-undef
          this.baseLayers.push(L.tileLayer(item))
        })

        // eslint-disable-next-line no-undef
        const map = L.map('map-multi', {
          center: [+this.field.longitude, +this.field.latitude],
          zoom: 18,
          zoomControl: false,
          maxZoom: 18,
          attributionControl: false,
          layers: this.baseLayers,
        })
        this.map = map

        // 创建图层
        this.map.on('pm:create', (e) => {
          this.layers.push(e.layer)
          this.map.pm.disableDraw()
        })

        // 移除图层
        this.map.on('pm:remove', (e) => {
          const index = this.getLeafletId(e)
          this.layers.splice(index, 1)
        })

        // eslint-disable-next-line no-undef
        this.featureLayerGroup = new L.FeatureGroup()
          .addTo(this.map)
          .bringToBack()
      },
      getLeafletId(e) {
        const id = e.layer._leaflet_id
        const index = this.latlngsArr.findIndex((val) => {
          return val.id === id
        })
        return index
      },
      async getGrids() {
        const {
          data: { data },
        } = await getGrids({ field_id: 6, grid_type_id: this.gridTypeId })
        this.grids = data
      },
      async getGridPartitions() {
        const {
          data: { data },
        } = await getGridPartitions({
          field_id: 6,
          grid_type_id: this.gridTypeId,
        })
        this.gridPartitions = data
      },
      async getGridType(id) {
        const { data } = await getGridType(id)
        this.gridType = data
      },
      async updateGridType(id, data) {
        const { msg } = await updateGridType(id, data)
        this.$baseMessage(msg, 'success', 'vab-hey-message-success')
      },
      onSuccess(response) {
        const { errorCode, msg, data } = response
        if (errorCode !== 0) {
          this.$message({
            message: (msg && `上传失败，失败原因：${msg}`) || '上传失败',
            type: 'error',
          })
          this.$emit('onError', data)
        } else {
          this.$baseMessage('操作成功', 'success')
          this.tableData = data.data
          this.centroids = data.centroids
        }
      },
      zoomUpdate(zoom) {
        this.zoom = zoom
      },
      centerUpdate(center) {
        this.center = center
      },
      handleDetail(row) {
        this.currentLayer = row
        this.handleAddGrid(row.data)
      },
      handleEdit(row) {
        this.$baseConfirm('确定将此分区设置为生效分区吗？', null, async () => {
          this.activeGrid(row.id)
        })
      },
      handleAddCell() {
        this.dialogVisible = true
      },
      cellSet() {
        this.$refs.cellSet.show()
      },
      drawReset() {
        this.clearKriging()
      },
      handleAddGrid(data) {
        this.polygons = []
        this.circlePolygons = []
        this.polygonsIntersect = []
        this.layers = []

        var center = turf.point([+this.field.latitude, +this.field.longitude])
        var radius = this.field.radius / 1000
        const angle = this.ruleForm.angle
        const workAngle = Math.abs(
          this.ruleForm.endAngle - this.ruleForm.startAngle
        )

        for (
          let i = this.ruleForm.startAngle / angle;
          i < this.ruleForm.startAngle / angle + workAngle / angle;
          i++
        ) {
          var bearing1 = i * angle
          var bearing2 = (i + 1) * angle

          var sector = turf.sector(center, radius, bearing1, bearing2)
          let latlngs = sector.geometry.coordinates[0]
          latlngs = latlngs.map((val) => [val[1], val[0]])
          // eslint-disable-next-line no-undef
          const polygon = L.polygon(latlngs, {
            color: 'rgb(51,136,255)',
            fillColor: 'red',
            fillOpacity: '0.4',
            weight: 2,
          })
          this.polygons.push(polygon)
        }

        // let distances = this.distances.map((val) => val.distance);
        let distances = []
        if (this.ruleForm.distances) {
          distances = uniqueArr(
            this.ruleForm.distances.map((val) => val.distance) || []
          )
        }

        distances.forEach((item) => {
          var bearing3 = 0
          var bearing4 = 360
          var sector1 = turf.sector(center, item / 1000, bearing3, bearing4)
          let latlngs = sector1.geometry.coordinates[0]
          latlngs = latlngs.map((val) => [val[1], val[0]])
          // eslint-disable-next-line no-undef
          const circlePolygon = L.polygon(latlngs, {
            color: 'rgb(51,136,255)',
            fillColor: 'red',
            fillOpacity: '0.4',
          })
          this.circlePolygons.push(circlePolygon)
        })

        const res = []
        this.polygons.forEach((item, index) => {
          const latlngs = item._latlngs[0].map((val) => [val.lat, val.lng])
          latlngs[latlngs.length] = latlngs[0]

          const temp = []
          this.circlePolygons.forEach((citem, cindex) => {
            const latlngsCircle = citem._latlngs[0].map((val) => [
              val.lat,
              val.lng,
            ])
            latlngsCircle[latlngsCircle.length] = latlngsCircle[0]

            var intersection = turf.intersect(
              turf.polygon([latlngs]),
              turf.polygon([latlngsCircle])
            )

            const semicircle = intersection.geometry.coordinates[0]

            temp.push({
              angle: (index + 1) * this.ruleForm.angle,
              distance: distances[cindex],
              polygon: semicircle,
            })
          })
          res.push(temp)
        })

        const polygons = []
        res.forEach((item, index) => {
          item.forEach((citem, cindex) => {
            if (cindex === 0) {
              polygons.push({
                polygon: citem.polygon,
                argstart: this.ruleForm.angle * index,
                argend: citem.angle,
                idx: index + 1,
                spstart: this.ruleForm.distances[cindex].spstart,
                spend: this.ruleForm.distances[cindex].spend,
                disstart: 0,
                disend: citem.distance,
              })
            } else {
              var difference = turf.difference(
                turf.polygon([citem.polygon]),
                turf.polygon([item[cindex - 1].polygon])
              )
              polygons.push({
                polygon: difference.geometry.coordinates[0],
                argstart: this.ruleForm.angle * index,
                argend: citem.angle,
                idx: index + 1,
                spstart: this.ruleForm.distances[cindex].spstart,
                spend: this.ruleForm.distances[cindex].spend,
                disstart: distances[cindex - 1],
                disend: citem.distance,
              })
            }
          })
        })

        polygons.reverse().forEach((item, index) => {
          const fillColor = this.stepsObjByLabels[data[index].labels]['color']
          const step = this.stepsObjByLabels[data[index].labels]['step']
          // eslint-disable-next-line no-undef
          const layer = L.polygon(item.polygon, {
            color: '#000',
            fillColor: '',
            fillOpacity: 0,
            weight: 1,
          }).addTo(this.map)

          layer.setStyle({
            fillColor: fillColor,
            fillOpacity: 1,
          })
          this.relation[layer._leaflet_id] = step

          layer.on('click', (e) => {
            e.target.setStyle({
              fillColor: this.stepsObj[this.step].color,
              fillOpacity: 1,
            })
            this.relation[e.sourceTarget._leaflet_id] = this.step
          })
          item.layer = layer
          item.area = turf.area(
            turf.polygon([item.polygon.map((val) => [val[1], val[0]])])
          )
          this.layers.push(item)
        })
      },
      drawFinish() {
        const index = this.gridType.steps.findIndex((item) => {
          return +item.step === +this.step
        })
        const step = this.gridType.steps[index]
        this.layers.forEach((item) => {
          if (!this.relation[item.layer._leaflet_id]) {
            item.layer.setStyle({
              fillColor: step.color,
              fillOpacity: 1,
            })
            item.color = step.color
            item.step = step.step
          }
        })
        this.$confirm('确定提交生成的新分区吗？', '操作确认', {
          type: 'warning',
        })
          .then(() => {
            const arr = []
            this.layers.reverse().forEach((item, index) => {
              const layer = item.layer
              const _leaflet_id = layer._leaflet_id
              const _latlngs = layer._latlngs[0]
              item.kml = _latlngs
                .map((val) => [val.lng, val.lat].join(','))
                .join(';')
              item.name =
                item.idx +
                '-' +
                (index + 1 - this.ruleForm.distances.length * (item.idx - 1))
              delete item.layer
              delete item.polygon
              if (this.relation[_leaflet_id]) {
                item.step = this.relation[_leaflet_id]
                item.color = this.stepsObj[this.step].color
              }
              arr.push(item)
            })
            const postData = {
              field_id: this.field.id,
              grid_type_id: this.gridType.id,
              start_angle: this.ruleForm.startAngle,
              end_angle: this.ruleForm.endAngle,
              angle: this.ruleForm.angle,
              grids: arr,
              created_user: this.username,
            }
            this.addGrid(postData)
          })
          .catch((e) => {
            console.log(e)
          })
      },
      // 清空图层
      clearKriging() {
        if (this.circleLayer) {
          this.map.removeLayer(this.circleLayer)
        }
        this.layers.reverse().forEach((item) => {
          delete item.layer
          delete item.polygon
        })
        this.featureLayerGroup.clearLayers()
      },
    },
  }
</script>

<style lang="scss" scoped>
  .content {
    height: 310px;
    line-height: 320px;
    text-align: center;
  }
  .btn-container {
    position: absolute;
    bottom: 24px;
    left: 24px;
    z-index: 9999;
  }
  .tooltip {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 999;
    display: flex;
    flex-direction: column;
    padding: 8px 8px;
    color: #333;
    cursor: pointer;
    background: rgba(255, 255, 255, 1);
    border-radius: 4px;
    box-shadow: 2px 2px 5px 1px rgba(0, 0, 0, 0.9);
    &:hover {
      background: rgba(255, 255, 255, 0.9);
    }
    span {
      font-size: 12px;
      text-align: center;
      &.iconfont {
        margin-bottom: 8px;
        font-size: 20px;
        color: #999;
      }
    }
  }
  .colors {
    position: absolute;
    top: 0;
    left: 12px;
    z-index: 999;
    dl {
      align-items: center;
      font-size: 12px;
      dt {
        width: 150px;
        height: 30px;
        line-height: 30px;
        color: #000;
        text-align: left;
        text-indent: 8px;
      }
    }
  }
</style>
